﻿// EPPlus 4.5.3.3 + Newtonsoft.Json 12.0.3 支持
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using Newtonsoft.Json;

namespace ExcelBlockLib
{
    public static class ConfigManager
    {
        private static readonly string configFilePath = Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "ExcelBlockLib", "path_config.json");

        public static string GetPath(string key)
        {
            if (!File.Exists(configFilePath)) return null;
            var json = File.ReadAllText(configFilePath);
            var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
            return dict != null && dict.ContainsKey(key) ? dict[key] : null;
        }

        public static void SetPath(string key, string path)
        {

            Directory.CreateDirectory(Path.GetDirectoryName(configFilePath));
            Dictionary<string, string> dict = new Dictionary<string, string>();
            if (File.Exists(configFilePath))
            {
                var json = File.ReadAllText(configFilePath);
                dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
            }
            dict[key] = path;
            File.WriteAllText(configFilePath, JsonConvert.SerializeObject(dict, Formatting.Indented));
        }
    }

    public static class ExcelBlockService
    {
        public static void AssignBlockIndexesFromImport(List<Dictionary<string, string>> blocks, string importPath)
        {
            // 分类 -> (已分配的类型代号, 该类型代号对应编号, 当前最大编号)
            var categoryTypeIndex = new Dictionary<string, Dictionary<string, string>>();
            var categoryMaxNum = new Dictionary<string, int>();

            // 1. 读取importPath表格里所有类型代号和编号，且区分分类
            if (File.Exists(importPath))
            {
                var oldBlocks = SafeLoad(importPath);
                foreach (var b in oldBlocks)
                {
                    if (!b.TryGetValue("材质类别", out var category) || !b.TryGetValue("类型代号", out var typeCode)) continue;

                    if (!categoryTypeIndex.ContainsKey(category))
                        categoryTypeIndex[category] = new Dictionary<string, string>();

                    if (b.TryGetValue("索引编号", out var idxVal) && !string.IsNullOrWhiteSpace(idxVal))
                    {
                        categoryTypeIndex[category][typeCode] = idxVal;
                        var arr = idxVal.Split('-');

                        // 手动检查字典并获取当前最大编号
                        if (arr.Length > 1 && int.TryParse(arr[1], out int n))
                        {
                            // 使用 ContainsKey 来检查是否存在该分类的最大编号，如果不存在则使用0
                            int currentMaxNum = categoryMaxNum.ContainsKey(category) ? categoryMaxNum[category] : 0;

                            // 如果新的编号大于当前最大编号，则更新
                            if (n > currentMaxNum)
                            {
                                categoryMaxNum[category] = n; // 更新当前最大编号
                            }
                        }
                    }
                }
            }


            // 2. 分类别分配编号，catIdx严格按sheet顺序来
            foreach (var group in blocks.GroupBy(b => b.ContainsKey("材质类别") ? b["材质类别"] : ""))
            {
                var category = group.Key;
                int catIdx = MaterialFieldMap.Keys.ToList().IndexOf(category) + 1;  // 根据类别在所有sheet中的顺序来分配索引

                if (!categoryTypeIndex.ContainsKey(category))
                    categoryTypeIndex[category] = new Dictionary<string, string>();
                if (!categoryMaxNum.ContainsKey(category))
                    categoryMaxNum[category] = 0;

                foreach (var b in group)
                {
                    if (!b.TryGetValue("类型代号", out var typeCode)) continue;

                    // 如果类型代号已存在，保留原有的索引编号
                    if (categoryTypeIndex[category].ContainsKey(typeCode))
                    {
                        b["索引编号"] = categoryTypeIndex[category][typeCode];
                    }
                    else
                    {
                        // 新类型代号，分配新的索引编号
                        int newNum = ++categoryMaxNum[category];
                        string idx = $"{catIdx}-{newNum}";  // 这里的索引编号就是按sheet顺序 + 新的编号
                        b["索引编号"] = idx;
                        categoryTypeIndex[category][typeCode] = idx;
                    }
                }
            }
        }


        public static Func<string, bool> GlobalConfirmOverwrite { get; set; } = null;

        private static readonly Dictionary<string, List<string>> MaterialFieldMap;
        public static Dictionary<string, List<string>> CurrentExportFieldMap = new Dictionary<string, List<string>>();

        static ExcelBlockService()
        {
            string defaultFieldPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "UserDatabase", "CADdatabase", "材料特性信息.xlsx");

            string configPath = ConfigManager.GetPath("FieldDef");
            string fieldPath = !string.IsNullOrWhiteSpace(configPath) ? configPath : defaultFieldPath;

            try
            {
                MaterialFieldMap = MaterialFieldLoader.LoadFieldMapFromExcel(fieldPath);
                Console.WriteLine("✅ 字段映射加载成功，共识别类别数：" + MaterialFieldMap.Count);
            }
            catch (Exception ex)
            {
                Console.WriteLine("⚠️ 字段定义加载失败：" + ex.Message);
                MaterialFieldMap = new Dictionary<string, List<string>>();
            }
        }




        public static void GenerateEmptyExcelIfNotExist(string path)
        {
            if (!File.Exists(path))
            {
                var dir = Path.GetDirectoryName(path);
                if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                GenerateEmptyExcel(path);
            }
        }

        public static void GenerateEmptyExcel(string path)
        {
            using (var package = new ExcelPackage())
            {
                foreach (var category in MaterialFieldMap.Keys)
                {
                    var fields = MaterialFieldMap[category];
                    if (fields == null || fields.Count == 0) continue;

                    var sheet = package.Workbook.Worksheets.Add(category);
                    for (int col = 0; col < fields.Count; col++)
                        sheet.Cells[1, col + 1].Value = fields[col];

                    sheet.Cells[1, fields.Count + 1].Value = "索引编号";
                }

                try
                {
                    package.SaveAs(new FileInfo(path));
                }
                catch (Exception ex)
                {
                    Console.WriteLine("❌ 保存文件失败：" + path);
                    Console.WriteLine("原因：" + ex.Message);
                }
            }
        }


        public static List<Dictionary<string, string>> SafeLoad(string path = null)
        {
            path = path ?? ConfigManager.GetPath("Import");
            if (string.IsNullOrWhiteSpace(path)) return new List<Dictionary<string, string>>();

            if (!File.Exists(path))
            {
                GenerateEmptyExcel(path);
                return new List<Dictionary<string, string>>();
            }

            var result = new List<Dictionary<string, string>>();
            using (var package = new ExcelPackage(new FileInfo(path)))
            {
                foreach (var sheet in package.Workbook.Worksheets)
                {
                    // 关键修改（实时字段顺序）
                    if (!CurrentExportFieldMap.ContainsKey(sheet.Name) && !MaterialFieldMap.ContainsKey(sheet.Name))
                    {
                        Console.WriteLine($"⚠️ 忽略未识别的Sheet: {sheet.Name}");
                        continue;
                    }

                    // 获取对应的字段列表，确保字段与表头顺序一致
                    var fields = CurrentExportFieldMap.ContainsKey(sheet.Name) ?
                                 CurrentExportFieldMap[sheet.Name] : MaterialFieldMap[sheet.Name];

                    // 确保表格的列名和字段名一致
                    var columnNames = sheet.Cells[1, 1, 1, sheet.Dimension.End.Column]
                                      .Select(cell => cell.Text.Trim())
                                      .ToList();

                    // 处理每行数据
                    for (int row = 2; row <= sheet.Dimension.End.Row; row++)
                    {
                        var block = new Dictionary<string, string> { ["材质类别"] = sheet.Name };

                        // 按照表头字段顺序读取每一列数据
                        for (int col = 0; col < fields.Count; col++)
                        {
                            var field = fields[col];
                            var columnIdx = columnNames.IndexOf(field);  // 找到对应的列索引

                            // 如果该字段存在，则填入相应的值
                            if (columnIdx >= 0)
                            {
                                var value = sheet.Cells[row, columnIdx + 1].Text.Trim();
                                block[field] = string.IsNullOrEmpty(value) ? "/" : value;
                            }
                            else
                            {
                                // 如果字段在表格中缺失，填充为默认值
                                block[field] = "/";
                            }
                        }

                        // 读取删除标记
                        var deletedCell = sheet.Cells[row, fields.Count + 2].Text.Trim();
                        if (deletedCell == "1")
                            block["__deleted__"] = "1";

                        result.Add(block);
                    }
                }
            }

            return result;
        }
        public static void EnsureAllBlocksHaveIndex(List<Dictionary<string, string>> blocks)
        {
            // 分组处理，保证每个分类下编号连续
            var groups = blocks.GroupBy(b => b.ContainsKey("材质类别") ? b["材质类别"] : "");
            foreach (var group in groups)
            {
                string category = group.Key;
                int catIdx = MaterialFieldMap.Keys.ToList().IndexOf(category) + 1;
                int idx = 1;
                foreach (var block in group)
                {
                    if (!block.ContainsKey("索引编号") || string.IsNullOrWhiteSpace(block["索引编号"]))
                    {
                        block["索引编号"] = $"{catIdx}-{idx}";
                    }
                    idx++;
                }
            }
        }


        public static List<Dictionary<string, string>> LoadAllBlocks(string filePath)
        {
            var result = new List<Dictionary<string, string>>();
            using (var package = new ExcelPackage(new FileInfo(filePath)))
            {
                foreach (var sheet in package.Workbook.Worksheets)
                {
                    if (!MaterialFieldMap.ContainsKey(sheet.Name)) continue;
                    var fields = MaterialFieldMap[sheet.Name];
                    for (int row = 2; row <= sheet.Dimension.End.Row; row++)
                    {
                        var block = new Dictionary<string, string> { ["材质类别"] = sheet.Name };
                        for (int col = 0; col < fields.Count; col++)
                        {
                            string field = fields[col];
                            string value = sheet.Cells[row, col + 1].Text.Trim();
                            block[field] = string.IsNullOrEmpty(value) ? "/" : value;
                        }

                        // 加载 __deleted__ 标记（位于最后一列）
                        var deletedCell = sheet.Cells[row, fields.Count + 2].Text.Trim();
                        if (deletedCell == "1")
                            block["__deleted__"] = "1";

                        result.Add(block);
                    }
                }
            }
            return result;
        }


        /// <summary>
        /// 获取分类在特性定义表中的顺序号（从1开始）
        /// </summary>
        public static string GetCategoryIndex(string category)
        {
            var allCategories = MaterialFieldMap.Keys.ToList();
            int index = allCategories.IndexOf(category);
            return index >= 0 ? (index + 1).ToString() : "0";
        }

        public static string AllocateTypeIndex(List<Dictionary<string, string>> blocks, string category)
        {
            var existNums = blocks
                .Where(b => b.ContainsKey("材质类别") && b["材质类别"] == category)
                .Where(b => b.ContainsKey("索引编号"))
                .Select(b =>
                {
                    var parts = b["索引编号"].Split('-');
                    int n;
                    return parts.Length > 1 && int.TryParse(parts[1], out n) ? n : 0;
                })
                .ToList();

            int newNum = existNums.Any() ? existNums.Max() + 1 : 1;
            string catIdx = GetCategoryIndex(category);
            return $"{catIdx}-{newNum}";
        }




        public static void AddOrUpdateBlock(
    List<Dictionary<string, string>> blocks,
    Dictionary<string, string> blockData,
    Func<string, bool> confirmOverwrite = null)
        {
            var key = GetUniqueKey(blockData);
            if (string.IsNullOrWhiteSpace(key)) return;
            string category = blockData.ContainsKey("材质类别") ? blockData["材质类别"] : "";

            // 查找是否存在
            var existing = blocks.FirstOrDefault(b =>
                GetUniqueKey(b) == key &&
                b.ContainsKey("材质类别") &&
                b["材质类别"] == category);

            // 保证表头字段一致，只保留MaterialFieldMap里的字段
            var fields = MaterialFieldMap.ContainsKey(category)
                ? new List<string>(MaterialFieldMap[category])
                : new List<string>();

            // 新参数补齐
            var newBlock = new Dictionary<string, string>();
            foreach (var field in fields)
            {
                newBlock[field] = blockData.ContainsKey(field) ? blockData[field] : "/";
            }

            if (existing != null)
            {
                // 保留索引编号
                newBlock["索引编号"] = existing.ContainsKey("索引编号")
                    ? existing["索引编号"]
                    : AllocateTypeIndex(blocks, category);

                // __deleted__标记（新数据覆盖后直接重置为"0"）
                newBlock["__deleted__"] = "0";

                bool allow = confirmOverwrite?.Invoke(key)
                    ?? GlobalConfirmOverwrite?.Invoke(key)
                    ?? true;
                if (allow)
                {
                    int idx = blocks.IndexOf(existing);
                    blocks[idx] = newBlock;
                }
            }
            else
            {
                // 新增类型代号，分配新编号
                newBlock["索引编号"] = AllocateTypeIndex(blocks, category);
                newBlock["__deleted__"] = "0";
                blocks.Add(newBlock);
            }
        }





        public static void AddOrUpdateBlocks(List<Dictionary<string, string>> blocks, List<Dictionary<string, string>> newItems)
        {
            foreach (var block in newItems)
                AddOrUpdateBlock(blocks, block);
        }

        public static void MarkBlockAsDeleted(List<Dictionary<string, string>> blocks, List<Dictionary<string, string>> deleteItems)
        {
            foreach (var item in deleteItems)
            {
                if (!item.ContainsKey("材质类别") || !item.ContainsKey("类型代号")) continue;

                string category = item["材质类别"];
                string key = item["类型代号"];

                var match = blocks.FirstOrDefault(b =>
                    b.ContainsKey("材质类别") && b["材质类别"] == category &&
                    b.ContainsKey("类型代号") && b["类型代号"] == key);

                if (match != null)
                    match["__deleted__"] = "1";
            }
        }


        public static void ExportBlocksByCategory(string exportPath, List<Dictionary<string, string>> blocks)
        {
            AssignBlockIndexesFromImport(blocks, ConfigManager.GetPath("Import"));
            if (blocks == null || string.IsNullOrWhiteSpace(exportPath)) return;

            var grouped = MaterialFieldMap.Keys.ToDictionary(
                cat => cat,
                cat => blocks.Where(b => b.ContainsKey("材质类别") && b["材质类别"] == cat).ToList());

            using (var package = new ExcelPackage())
            {
                foreach (var category in grouped.Keys)
                {
                    var sheet = package.Workbook.Worksheets.Add(category);
                    var list = grouped[category];

                    // 表头严格用定义表，不再动态扩展
                    var fields = MaterialFieldMap.ContainsKey(category)
                        ? new List<string>(MaterialFieldMap[category])
                        : new List<string>();
                    fields.Add("索引编号");
                    fields.Add("__deleted__");

                    // 写表头
                    for (int col = 0; col < fields.Count; col++)
                        sheet.Cells[1, col + 1].Value = fields[col];

                    // 写数据
                    for (int row = 0; row < list.Count; row++)
                    {
                        var block = list[row];
                        bool isDeleted = block.ContainsKey("__deleted__") && block["__deleted__"] == "1";

                        for (int col = 0; col < fields.Count; col++)
                        {
                            var field = fields[col];
                            string value;
                            if (field == "索引编号")
                                value = block.ContainsKey("索引编号") ? block["索引编号"] : "";
                            else if (field == "__deleted__")
                                value = block.ContainsKey("__deleted__") ? block["__deleted__"] : "0";
                            else
                                value = block.ContainsKey(field) ? block[field] : "/";

                            var cell = sheet.Cells[row + 2, col + 1];
                            cell.Value = value;

                            // 逻辑删除高亮（不高亮__deleted__字段本身）
                            if (isDeleted)
                            {
                                cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
                                cell.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
                            }

                        }
                    }
                }
                package.SaveAs(new FileInfo(exportPath));
            }
        }





        public static string GetUniqueKey(Dictionary<string, string> row)
        {
            return row.ContainsKey("类型代号") ? row["类型代号"] : "";
        }

    }
}